package secret;

import com.fasterxml.jackson.databind.ObjectMapper;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.Base64;

public class AES_demo {

    private static final String AES_ALGORITHM = "AES";
    private static final String AES_CIPHER = "AES/CBC/PKCS5Padding";
    private static final int IV_LENGTH = 16; // 128 bits

    /**
     * 使用字符串密钥加密
     * @param plainText 明文
     * @param key 密钥字符串
     * @return Base64编码的加密结果(包含IV)
     */
    public static String encrypt(String plainText, String key) throws Exception {
        // 生成固定长度的密钥(128/192/256位)
        byte[] keyBytes = generateKey(key);

        // 生成随机初始化向量(IV)
        byte[] iv = new byte[IV_LENGTH];
        java.security.SecureRandom random = new java.security.SecureRandom();
        random.nextBytes(iv);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);

        // 创建密钥规范
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, AES_ALGORITHM);

        // 加密
        Cipher cipher = Cipher.getInstance(AES_CIPHER);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
        byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));

        // 组合IV和加密数据(IV不需要保密，但需要用于解密)
        byte[] combined = new byte[iv.length + encrypted.length];
        System.arraycopy(iv, 0, combined, 0, iv.length);
        System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length);

        return Base64.getEncoder().encodeToString(combined);
    }

    /**
     * 使用字符串密钥解密
     * @param encryptedText Base64编码的加密文本(包含IV)
     * @param key 密钥字符串
     * @return 解密后的明文
     */
    public static String decrypt(String encryptedText, String key) throws Exception {
        // 生成固定长度的密钥
        byte[] keyBytes = generateKey(key);

        // 解码Base64并分离IV和加密数据
        byte[] combined = Base64.getDecoder().decode(encryptedText);
        byte[] iv = new byte[IV_LENGTH];
        byte[] encrypted = new byte[combined.length - IV_LENGTH];
        System.arraycopy(combined, 0, iv, 0, IV_LENGTH);
        System.arraycopy(combined, IV_LENGTH, encrypted, 0, encrypted.length);

        // 创建密钥规范和IV
        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, AES_ALGORITHM);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);

        // 解密
        Cipher cipher = Cipher.getInstance(AES_CIPHER);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
        byte[] decrypted = cipher.doFinal(encrypted);

        return new String(decrypted, StandardCharsets.UTF_8);
    }

    /**
     * 从字符串生成固定长度的密钥(128/192/256位)
     */
    private static byte[] generateKey(String key) throws Exception {
        // 使用SHA-256哈希确保密钥长度符合要求
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(key.getBytes(StandardCharsets.UTF_8));

        // 根据需求截取适当长度:
        // AES-128: 16字节, AES-192: 24字节, AES-256: 32字节
        byte[] truncatedKey = new byte[32]; // 使用AES-256
        System.arraycopy(hash, 0, truncatedKey, 0, truncatedKey.length);

        return truncatedKey;
    }

    public static void main(String[] args) throws Exception {
        String originalText = "这是一段需要加密的敏感数据";
        String secretKey = "MySecretKey123!"; // 用户提供的密钥

        System.out.println("原始文本: " + originalText);

        // 加密
        String encryptedText = encrypt(originalText, secretKey);
        System.out.println("加密结果: " + encryptedText);

        // 解密
        String decryptedText = decrypt(encryptedText, secretKey);
        System.out.println("解密结果: " + decryptedText);


        Teacher teacher = new Teacher("杨通通", 31, "物理");
        ObjectMapper mapper = new ObjectMapper();
        byte[] bytes = mapper.writeValueAsBytes(teacher);
        Base64.Encoder encoder = Base64.getEncoder();
        String encodedTeacher = encoder.encodeToString(bytes);
        System.out.println("teacher转base64:"+encodedTeacher);
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] decode = decoder.decode(encodedTeacher);
        Teacher decodedTeacher = mapper.readValue(decode, Teacher.class);
        System.out.println(decodedTeacher);
    }
}
